
package com.hlkj.pay.app.merchant.ext.impl.haike.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.haike.HaikePayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.haike.constant.HaikePayConstant;
import com.hlkj.pay.app.merchant.ext.impl.haike.constant.HaikePayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.haike.dto.HaikePayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.haike.dto.HaikePayConfig;
import com.hlkj.pay.app.merchant.ext.impl.haike.dto.resp.HaikePrePayResp;
import com.hlkj.pay.app.merchant.ext.impl.haike.handler.HaikePayCommonParamsHandle;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 扫码统一下单
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = HaikePayExtConstant.JSAPI_PAY)
public class HaikePayJsApiPayOrderExtPt extends HaikePaySceneCommonPayOrder implements HaikePayScenePayOrderExtPt {

    private final HaikePayCommonParamsHandle haikePayCommonParamsHandle;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {

        log.info("海科 JSAPI 请求参数:{}", JsonUtils.toJsonString(channelPayOrderContext));
        CommonResult<HaikePayConfig> haikePayConfigCommonResult = haikePayCommonParamsHandle.haikePayConfig(channelPayOrderContext.getProviderChannelConfigDO(),
                channelPayOrderContext.isTest());
        if (!haikePayConfigCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(haikePayConfigCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        // 支付订单信息
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 支付方式信息
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 商户通道信息
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        // 海科配置信息
        HaikePayConfig haikePayConfig = haikePayConfigCommonResult.getData();
        // 额外参数信息
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();

        if (extra == null || !StringUtils.hasText(extra.getUserId())) {
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
            channelPayOrderContext.setRemark("海科 "+ PayEnums.PAY_TYPE.fromByCode(payWayDO.getType()).getType() +" 提交 JSAPI 支付 没有提交userId");
            return;
        }

        try {
            HaikePayAppChannelParams haikeAppChannelParams = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), HaikePayAppChannelParams.class);

            String payway = haikePayCommonParamsHandle.getPayWay(payWayDO);
            if(StrUtil.isEmpty(payway)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("海科提交JSAPI支付 支付类型: "+payWayDO.getType()+" 不支持");
                return;
            }

            Map<String,Object> reqData = new HashMap<>();
            reqData.put("agent_no", haikePayConfig.getFtpName());

            // 支付方式判断
            switch (payway) {
                // 微信支付时使用：微信分配的公众账号 ID
                case "WX":
                    reqData.put("appid", extra.getSubAppid());
                    break;
            }

            reqData.put("openid", extra.getUserId());
            reqData.put("req_id", IdUtil.getSnowflakeNextIdStr());
            reqData.put("merch_no",haikeAppChannelParams.getSubMchId());
            reqData.put("pay_type", payway);
            reqData.put("pay_mode", "JSAPI");
            reqData.put("out_trade_no", payOrderDO.getPayOrderNo());
            reqData.put("total_amount", NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));
            reqData.put("pn", haikeAppChannelParams.getPn());
            reqData.put("notify_url", channelPayOrderContext.getNotifyUrl());

            log.info("海科提交JSAPI支付 请求参数:{}", JSONUtil.toJsonStr(reqData));
            String result = haikePayCommonParamsHandle.requestPostApi(HaikePayConstant.ORDER_PRE_PAY_URL,reqData,haikePayConfig);
            log.info("海科提交JSAPI支付 返回参数:{}", result);
            if(StrUtil.isEmpty(result)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("海科提交JSAPI支付请求失败");
                return;
            }
            // 结果转对象
            HaikePrePayResp prePayRes = JSONUtil.toBean(result,HaikePrePayResp.class);
            // 通信状态和支付状态都成功
            if(HaikePayConstant.OK.equals(prePayRes.getResult_code())){
                channelPayOrderContext.setInsOrderNo(prePayRes.getTrade_no());
                switch (payway) {
                    // 微信 走简易支付
                    case "WX":
                        channelPayOrderContext.setPayDataType("data");
                        channelPayOrderContext.setPayInfo(prePayRes.getWc_pay_data());
                        break;
                    case "ALI":
                        channelPayOrderContext.setPayDataType("data");
                        Map<String,Object> tradeNOMap = new HashMap<>();
                        tradeNOMap.put("tradeNo",prePayRes.getAli_trade_no());
                        channelPayOrderContext.setPayInfo(JSONUtil.toJsonStr(tradeNOMap));
                        break;
                    case "UNIONQR":
                        channelPayOrderContext.setPayDataType("pay_url");
                        channelPayOrderContext.setPayInfo(prePayRes.getUniqr_redirect_url());
                        break;
                }
            }else{
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark(prePayRes.getResult_msg());
            }
        }catch (Exception e) {
            log.error("海科提交JSAPI支付 请求失败, error: {}",e);
            channelPayOrderContext.setRemark("海科提交JSAPI支付 请求失败, error: " + e);
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
